package com.clei.utils;

import com.clei.dto.ReadPropertyDesc;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * read util
 *
 * @author Y
 */
public class ReadUtil {

    /**
     * toEntity
     *
     * @param propertyList 属性描述list
     * @param entity       T
     * @param <T>          泛型
     */
    public static <T> void toEntity(List<ReadPropertyDesc> propertyList, T entity) {
        // fields
        Field[] fields = entity.getClass().getDeclaredFields();
        Map<String, Field> fieldMap = new HashMap<>(fields.length);
        for (Field field : fields) {
            field.setAccessible(Boolean.TRUE);
            fieldMap.put(field.getName(), field);
        }
        // read
        Scanner input = SystemUtil.input();
        for (ReadPropertyDesc property : propertyList) {
            Field field = fieldMap.get(property.getKey());
            if (null == field) {
                PrintUtil.log("未知属性 key : {}, desc : {}", property.getKey(), property.getDesc());
                continue;
            }
            PrintUtil.print(property.getDesc());
            String value = input.nextLine();
            if (null == value) {
                continue;
            }
            // 转换
            property.setValue(value);
            Class<?> fieldClass = field.getType();
            Object newValue = String.class == fieldClass ? value : valueOf(value, fieldClass);
            try {
                field.set(entity, newValue);
            } catch (Exception e) {
                PrintUtil.log("setValue error ");
            }
        }
        printReadValue(propertyList);
    }

    /**
     * toEntity
     *
     * @param propertyList 属性描述list
     * @param valueMap     Map
     */
    public static <T> void toMap(List<ReadPropertyDesc> propertyList, Map<String, String> valueMap) {
        // read
        Scanner input = SystemUtil.input();
        for (ReadPropertyDesc property : propertyList) {
            PrintUtil.print(property.getDesc());
            String value = input.nextLine();
            property.setValue(value);
            valueMap.put(property.getKey(), value);
        }
        printReadValue(propertyList);
    }

    /**
     * printReadValue
     *
     * @param propertyList 属性描述list
     */
    private static void printReadValue(List<ReadPropertyDesc> propertyList) {
        for (ReadPropertyDesc property : propertyList) {
            PrintUtil.log("{}{}", property.getDesc(), property.getValue());
        }
    }

    /**
     * valueOf
     *
     * @param value string value
     * @param clazz class
     * @return Object
     */
    private static Object valueOf(String value, Class<?> clazz) {
        try {
            Method method = clazz.getDeclaredMethod("valueOf", String.class);
            boolean isStatic = Modifier.isStatic(method.getModifiers());
            Class<?> returnType = method.getReturnType();
            if (isStatic && clazz == returnType) {
                return method.invoke(null, value);
            }
            PrintUtil.log("valueOf fail value : {}, class : {}, isStatic : {}, returnType : {}", value, clazz, isStatic, returnType);
            return null;
        } catch (Exception e) {
            PrintUtil.log("valueOf error value : {}, class : {}", value, clazz, e);
            return null;
        }
    }
}